﻿using AnalyStock.DataAnalysis;

namespace AnalyStock.DataManage;
/// <summary>
/// 系统公用数据集合定义、扩展静态处理方法
/// </summary>
internal struct AppCollection
{
    //K线日蜡烛集合
    internal static IList<CandlePoint> CandlePoints { get; set; }
    //判断K线走势抽样点集合
    internal static IList<SamplePoint> SamplePoints { get; set; }
    //个股主要财务指标集合
    internal static IList<DynamicFinancialIndex> FinancialIndexs { get; set; }
    //全部上市股票集合
    internal static IList<StockInfo> StockInfos { get; set; }   
    //自选股票集
    internal static IList<SelectStock> SelectStocks { get; set; }
    //股票分类概念集
    internal static IList<Conception> Conceptions { get; set; }

    //均线集合   
    internal static IList<MAPoint>[] MaOfKline = new IList<MAPoint>[6];
    internal static IList<MAPoint>[] MaOfVol = new IList<MAPoint>[2];

    //策略选股的数据集合
    internal static IList<StockKeyIndicators> SeleStockKeyIndicators { get; set; }
}

/// <summary>
/// 查询K线蜡烛点扩展方法
/// </summary>
internal static class QueryCandlePointsExtension
{
    //倍量,当日为红色倍量,当日绿色倍量，涨停
    internal enum CandleType
    {
        DoubleVol, RedDoubleVol, GreenDoubleVol, SkyrocKeting, All
    }
    private static Func<CandlePoint, bool> SelectPredicate(CandleType qtype)
    {
        return qtype switch
        {
            CandleType.DoubleVol => p => p.IsDoubleVol,
            CandleType.RedDoubleVol => p => p.IsDoubleVol && p.IsCloseUpOpen,
            CandleType.SkyrocKeting => p => p.IsSkyrocketing,
            CandleType.All => n => true,
            _ => n => false
        };
    }

    internal static IEnumerable<CandlePoint> TakePoints(
        this IList<CandlePoint> list, CandleType qtype)
    {
        return list.Where(SelectPredicate(qtype));
    }

    internal static IEnumerable<CandlePoint> TakeLastDayPoints(
        this IList<CandlePoint> list, CandleType seleQueryType, int days)
    {
        return list.TakeLast(days).Where(SelectPredicate(seleQueryType));
    }

    internal static IEnumerable<float> TakeCloseArray(
        this IList<CandlePoint> list)
    {
        return list.Select(n => n.Close).ToArray();
    }

    internal static IEnumerable<float> TakeCloseArray(
        this IList<CandlePoint> list, Func<CandlePoint, bool> wherefunc)
    {
        return list.Where(wherefunc).Select(n => n.Close);
    }

}
/// <summary>
/// 查询K线拐点集合扩展方法
/// </summary>
internal static class QueryInflectPointsExtension
{
    internal enum InflectPType
    {
        //顶部点，底部点，起始点，结尾点，全部点
        Top, Bottom, NotTop, NotBottom, NotStartEnd, Start, End, All
    }

    //Func的模式，会将全表提取到内存中执行，大型查询不建议使用
    private static Func<SamplePoint, bool> SelectPredicate(InflectPType qtype)
    {
        return qtype switch
        {
            InflectPType.Top => p => p.TrendType is "↓", //顶点
            InflectPType.NotBottom => p => p.TrendType is not "↑", //包括顶点、StartP,EndP            
            InflectPType.Bottom => p => p.TrendType is "↑", //底点
            InflectPType.NotTop => p => p.TrendType is not "↓", //包括底点，startP，EndP
            InflectPType.NotStartEnd => p => p.TrendType is not ("start" or "end"), //不包括初始和结尾点
            InflectPType.Start => p => p.TrendType is "start", //初始点
            InflectPType.End => p => p.TrendType is "end", //结尾点
            InflectPType.All => p => true,
            _ => p => false
        };
    }

    internal static IEnumerable<SamplePoint> TakePoints(
        this IList<SamplePoint> list, InflectPType queryType)
    {
        return list.Where(SelectPredicate(queryType));
    }

    internal static IEnumerable<float> TakeCloseArray(
        this IList<SamplePoint> list, InflectPType qtype)
    {
        return list.Where(SelectPredicate(qtype)).Select(n => n.Close);
    }
    internal static IEnumerable<T1> TakeArray<T1>(this IEnumerable<SamplePoint> ienum, Func<SamplePoint, T1> result)
    {
        return ienum.Select(result);
    }
    internal static IEnumerable<T1> TakeArray<T, T1>(this IEnumerable<T> ienumT, T1 t)
    {
        static Func<T, T1> func(T1 t)
        {
            return T => t;
        }
        return ienumT.Select(func(t));
    }
}

/// <summary>
/// 迭代集合扩展处理方法
/// </summary>
public static class EnumerableExtension
{
    /// <summary>
    ///     同时获取集合的最大最小值
    /// </summary>    
    public static (TResult Max, TResult Min) MaxMinFloat<TSource, TResult>
        (this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        where TResult : struct, IFloatingPoint<TResult>
    {
        if (source == null)
        {
            throw new ArgumentNullException("the collection is null...");
        }

        if (selector == null)
        {
            throw new ArgumentNullException("the func is null...");
        }

        using (var enumerator = source.GetEnumerator())
        {
            if (!enumerator.MoveNext())
            {
                throw new NoNullAllowedException("the collection is empty...");
            }

            var val = selector(enumerator.Current);
            while (TResult.IsNaN(val))
            {
                if (!enumerator.MoveNext())
                {
                    return (val, val);
                }

                val = selector(enumerator.Current);
            }
            TResult valMin = val, valMax = val;
            while (enumerator.MoveNext())
            {
                val = selector(enumerator.Current);
                if (TResult.IsNaN(val))
                {
                    continue;
                }

                if (val > valMax)
                {
                    valMax = val;
                }

                if (val < valMin)
                {
                    valMin = val;
                }
            }
            return (valMax, valMin);
        }
    }

    /// <summary>
    ///     集合内元素（此处元素一般为可迭代类型）,对集合元素逐一执行匿名方法。
    ///     链式形式代替ForEach语句，功能一样，方便语句编辑。
    /// </summary>
    /// <param name="source"></param>
    /// <param name="action"></param>
    /// <typeparam name="TSource"></typeparam>
    public static void ForEach<TSource>
        (this IEnumerable<TSource> source, Action<TSource> action)
    {
        if (source is null)
        {
            throw new ArgumentNullException("the collection is null...");
        }
        using (var enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                action(enumerator.Current);
            }
        }
    }
}